/*
 *  Created on: Feb 18, 2013
 *      Author: Aaron Kaufman
 */

#include <windows.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include "ProcessScheduler.h"
#include "cpu.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "data.h"
#include "sharedMemory.h"
#include <unistd.h>




int run(CPU* cpu){
	return cpu->current_process->data.funct(&(cpu->current_process->data));
}

char* getProcessName(int (* funct)(tdata_t *data)){
	char* name = malloc(40);
	if (funct == next_pro_instr){
		strcpy(name, "Producer");
	}
	if (funct == next_con_instr){
		strcpy(name, "Consumer");
	}
	if (funct == next_calc_instr){
		strcpy(name, "Calculator");
	}
	return name;
}

void printStatus(ScheduleType type, CPU* cpu){
	char schedule_type [30];
	if (type == ROUND_ROBIN){
		strcpy(schedule_type, "Round Robin");
	}
	else if (type==PRIORITY){
		strcpy(schedule_type, "Priority");
	}
	else if (type == LOTTERY){
		strcpy(schedule_type, "Lottery");
	}

	printf("\nSchedule Type:  %s\n", schedule_type);
	printf("Process Statuses:  \n");
	fflush(stdout);
	int i = 0;
	Process* processes = cpu->process_scheduler.process_list.processes;
	for (i = 0; i < cpu->process_scheduler.process_list.size; i++){
		char name[40];
		strcpy(name, getProcessName(processes[i].data.funct));
		char status[40];
		if (processes[i].state == BLOCKED){
			strcpy(status, "Blocked");
		}
		else if (processes[i].state == RUNNABLE){
			strcpy(status, "Runnable ");
		}
		else{
			strcpy(status, "Running");
		}
		printf("%s : %s\n", name, status);
		fflush(stdout);
	}
}

void runCPU(ScheduleType type, CPU* cpu){
	buildNewSchedule(type, &cpu->process_scheduler);//Data is correct after this step for each process in process schedule.
	cpu-> current_process = getNextProcess(&cpu->process_scheduler);
	 cpu->current_process->state = RUNNING;

	printStatus(type, cpu);

	char* name = malloc(40);
	int instruction_calls = 0;
	int blocked_calls = 0;
	while(1){
		int blocked = run(cpu); //1 signifies that it's blocked

		if (blocked == -1){
			//Sleep(500);
			//printf("Current process : %d\n", cpu->process_scheduler.scheduler.current_process);

			blocked_calls ++;
			 cpu->current_process->state = BLOCKED;
			fflush(stdout);

			name =  getProcessName(cpu->current_process->data.funct);

			printf("%s process has blocked", name);
			printf(" after %d instructions.", instruction_calls);

			cpu->current_process = getNewProcess(cpu->current_process, &cpu->process_scheduler);
			cpu->current_process->state = RUNNING;

			 name =  getProcessName(cpu->current_process->data.funct);
			 printf("\n\nStarting %s process.\n", name);
			printStatus(type, cpu);
			fflush(stdout);
			instruction_calls = 0;
			//printStatus(type, cpu);
		}
		else{
			 cpu->current_process->state = RUNNING;
			instruction_calls++;
		}

		if (cpu->clock_interrupt == 1){
			 cpu->current_process->state = RUNNABLE;
			 cpu->current_process = getNextProcess(&cpu->process_scheduler);
			 name =  getProcessName(cpu->current_process->data.funct);
			 cpu->clock_interrupt = 0;
			 cpu->current_process->state = RUNNING;
			 printf("\n\nClock interrupt has occurred.  Next task: %s\n", name);
			 printf("Between this interrupt and the last, %d instructions were run.\n", instruction_calls);
			 fflush(stdout);


			printStatus(type, cpu);
			instruction_calls = 0;
		}
	}
}



void doClockInterrupt(CPU* cpu){
	cpu->clock_interrupt = 1;
}

void addProcessToCPUProcessList(int (* runProcess)(tdata_t *data), int priority, CPU* cpu, sharedMemory_t* mem, tdata_t* data){
	ProcessList* cpu_process_list = &cpu->process_scheduler.process_list;
	Process* process = &cpu->process_scheduler.process_list.processes[cpu_process_list->size];
	process->state = RUNNABLE;
	process->data = *data;
	process->data.funct = runProcess;
	process->priority = priority;
	cpu_process_list->size++;


}

void createCPU(CPU* cpu){
	cpu->clock_interrupt = 0;
	cpu->process_scheduler.scheduler.size = 0;
	cpu->process_scheduler.process_list.size=0;
	cpu->process_scheduler.scheduler.current_process=0;
}

void keyboardInterrupt(CPU* cpu, char* string, *data){

	printf("Keyboard interrupt occurs, printed = %s\n" , string);
	fflush(stdout);
}




